package fr.vince.gui;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import fr.vince.montecarlo.Action;
import fr.vince.montecarlo.MonteCarlo;
import fr.vince.montecarlomultithread.MonteCarloMultiThread;

/**
 * abstract class for slider modification listener
 * @author Vince
 *
 */
abstract class AbstractChangerListener implements ChangeListener {
}

/**
 * main frame of the application
 * @author Vince
 *
 */
public class MainView extends JFrame {
	private JTextField actualPrice;
	private JTextField strikePrice;
	private JSlider sliderTime;
	private JLabel textTime;
	private JTextField interest;
	private JTextField cost;
	private JSlider sliderSteps;
	private JLabel textSteps;
	private JSlider sliderSimulation;
	private JLabel textSimulation;
	private JTextField volatility;
	private JComboBox<String> callPut;
	private JComboBox<String> fileList;
	private JButton launch;
	private JLabel result;
	private JLabel timeSpent;
	private JCheckBox multiThread;
	private JProgressBar progressBar;

	/**
	 * default constructor
	 */
	public MainView() {
		String[] comboCnt = new String[2];
		comboCnt[0] = "call";
		comboCnt[1] = "put";
		callPut = new JComboBox<String>(comboCnt);
		String[] filenames = new String[10];
		filenames[0] = "file 1";
		filenames[1] = "file 2";
		filenames[2] = "file 3";
		filenames[3] = "file 4";
		filenames[4] = "file 5";
		filenames[5] = "file 6";
		filenames[6] = "file 7";
		filenames[7] = "file 8";
		filenames[8] = "file 9";
		filenames[9] = "file 10";
		fileList = new JComboBox<String>(filenames);
		fileList.addActionListener(new AbstractAction() {

			@Override
			public void actionPerformed(ActionEvent e) {
				JComboBox obj = (JComboBox) e.getSource();

				MainView.this.loadFromFile((String) obj.getSelectedItem());
			}

		});
		Dimension dim = new Dimension(100, 20);

		actualPrice = new JTextField();
		actualPrice.setPreferredSize(dim);
		strikePrice = new JTextField();
		strikePrice.setPreferredSize(dim);
		sliderTime = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
		textTime = new JLabel();
		sliderTime.addChangeListener(new AbstractChangerListener() {

			@Override
			public void stateChanged(ChangeEvent e) {
				// TODO Auto-generated method stub
				JSlider obj = (JSlider) e.getSource();
				MainView.this.textTime.setText("" + (double) obj.getValue()
						/ 10);
			}

		});
		textTime.setText("" + (double) sliderTime.getValue() / 10);

		interest = new JTextField();
		interest.setPreferredSize(dim);
		cost = new JTextField();
		cost.setPreferredSize(dim);
		sliderSteps = new JSlider(JSlider.HORIZONTAL, 0, 1000, 500);
		textSteps = new JLabel();
		sliderSteps.addChangeListener(new AbstractChangerListener() {

			@Override
			public void stateChanged(ChangeEvent e) {
				// TODO Auto-generated method stub
				JSlider obj = (JSlider) e.getSource();
				MainView.this.textSteps.setText("" + obj.getValue());
			}

		});
		textSteps.setText("" + sliderSteps.getValue());

		sliderSimulation = new JSlider(JSlider.HORIZONTAL, 0, 2000, 1000);
		textSimulation = new JLabel();
		sliderSimulation.addChangeListener(new AbstractChangerListener() {

			@Override
			public void stateChanged(ChangeEvent e) {
				// TODO Auto-generated method stub
				JSlider obj = (JSlider) e.getSource();
				MainView.this.textSimulation.setText("" + obj.getValue() * 100);
			}

		});
		textSimulation.setText("" + sliderSimulation.getValue() * 100);

		volatility = new JTextField();
		volatility.setPreferredSize(dim);

		launch = new JButton("launch");
		result = new JLabel("No result yet");
		timeSpent = new JLabel("No result yet");
		multiThread = new JCheckBox();
		multiThread.addActionListener(new AbstractAction(){

			@Override
			public void actionPerformed(ActionEvent arg0) {
				if(MainView.this.multiThread.isSelected())
					MainView.this.progressBar.setVisible(false);
				else
					MainView.this.progressBar.setVisible(true);	
			}
			
		});
		
		progressBar = new JProgressBar();
		/*progressBar.setMaximum(arg0);
		progressBar.setValue(arg0);*/

		launch.addActionListener(new AbstractAction() {

			@Override
			public void actionPerformed(ActionEvent e) {
				Object src = e.getSource();

				if (src == MainView.this.launch) {
					MainView.this.launch.setEnabled(false);
					MainView.this.launch.setText("Computation in progress...");
					final long start = System.nanoTime();
					if (MainView.this.multiThread.isSelected()) {
						(new SwingWorker() {
							Double res;

							@Override
							protected Object doInBackground() throws Exception {
								MonteCarloMultiThread mc = new MonteCarloMultiThread(
										MainView.this.callPut
												.getSelectedIndex() == 0 ? Action.CALL
												: Action.PUT,
										Double.parseDouble(MainView.this.actualPrice
												.getText()),
										Double.parseDouble(MainView.this.strikePrice
												.getText()),
										(double) MainView.this.sliderTime
												.getValue() / 10,
										Double.parseDouble(MainView.this.interest
												.getText()),
										Double.parseDouble(MainView.this.cost
												.getText()),
										Double.parseDouble(MainView.this.volatility
												.getText()),
										MainView.this.sliderSteps.getValue(),
										MainView.this.sliderSimulation
												.getValue() * 100);
								res = mc.doMonteCarlo();
								return null;
							}

							@Override
							protected void done() {
								try {
									MainView.this.result.setText(String.format(
											"%f", res));
									MainView.this.timeSpent.setText(""
											+ ((System.nanoTime() - start) / 1000000000.0)
											+ " s");
								} catch (Exception ignore) {
								} finally {
									MainView.this.launch.setEnabled(true);
									MainView.this.launch.setText("launch");
								}
							}
						}).execute();

					} else {
						(new SwingWorker() {
							Double res;

							@Override
							protected Object doInBackground() throws Exception {
								MonteCarlo mc = new MonteCarlo(
										MainView.this.callPut
												.getSelectedIndex() == 0 ? Action.CALL
												: Action.PUT,
										Double.parseDouble(MainView.this.actualPrice
												.getText()),
										Double.parseDouble(MainView.this.strikePrice
												.getText()),
										(double) MainView.this.sliderTime
												.getValue() / 10,
										Double.parseDouble(MainView.this.interest
												.getText()),
										Double.parseDouble(MainView.this.cost
												.getText()),
										Double.parseDouble(MainView.this.volatility
												.getText()),
										MainView.this.sliderSteps.getValue(),
										MainView.this.sliderSimulation
												.getValue() * 100);
								res = mc.doMonteCarlo(progressBar);
								return null;
							}

							@Override
							protected void done() {
								try {
									MainView.this.result.setText(String.format(
											"%f", res));
									MainView.this.timeSpent.setText(""
											+ ((System.nanoTime() - start) / 1000000000.0)
											+ " s");
								} catch (Exception ignore) {
								} finally {
									MainView.this.launch.setEnabled(true);
									MainView.this.launch.setText("launch");
								}
							}
						}).execute();

					}

				}
			}

		});
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		initView();
		pack();
	}

	/**
	 * initialize the grid organization for the view
	 */
	private void initView() {
		this.setLayout(new GridBagLayout());
		GridBagConstraints cons = new GridBagConstraints();

		cons.gridx = 0;
		cons.gridy = 0;
		add(new JLabel("Model : "), cons);
		cons.gridx = 1;
		add(fileList, cons);

		cons.gridx = 0;
		cons.gridy = 1;
		add(new JLabel("Action : "), cons);
		cons.gridx = 1;
		add(callPut, cons);

		cons.gridy = 2;
		cons.gridx = 0;
		add(new JLabel("actual price : "), cons);
		cons.gridx = 1;
		add(actualPrice, cons);

		cons.gridy = 3;
		cons.gridx = 0;
		add(new JLabel("strike price : "), cons);
		cons.gridx = 1;
		add(strikePrice, cons);

		cons.gridy = 4;
		cons.gridx = 0;
		add(new JLabel("time : "), cons);
		cons.gridx = 1;
		add(sliderTime, cons);
		cons.gridx = 2;
		add(textTime, cons);

		cons.gridy = 5;
		cons.gridx = 0;
		add(new JLabel("interest : "), cons);
		cons.gridx = 1;
		add(interest, cons);

		cons.gridy = 6;
		cons.gridx = 0;
		add(new JLabel("cost : "), cons);
		cons.gridx = 1;
		add(cost, cons);

		cons.gridy = 7;
		cons.gridx = 0;
		add(new JLabel("volatility : "), cons);
		cons.gridx = 1;
		add(volatility, cons);

		cons.gridy = 8;
		cons.gridx = 0;
		add(new JLabel("steps : "), cons);
		cons.gridx = 1;
		add(sliderSteps, cons);
		cons.gridx = 2;
		add(textSteps, cons);

		cons.gridy = 9;
		cons.gridx = 0;
		add(new JLabel("simulation : "), cons);
		cons.gridx = 1;
		add(sliderSimulation, cons);
		cons.gridx = 2;
		add(textSimulation, cons);

		cons.gridy = 10;
		cons.gridx = 0;
		add(new JLabel("Result : "), cons);
		cons.gridx = 1;
		add(result, cons);

		cons.gridy = 11;
		cons.gridx = 0;
		add(new JLabel("Time spent : "), cons);
		cons.gridx = 1;
		add(timeSpent, cons);

		cons.gridy = 12;
		cons.gridx = 0;
		add(new JLabel("Multi thread : "), cons);
		cons.gridx = 1;
		add(multiThread, cons);
		
		cons.gridy = 13;
		cons.gridx = 0;
		add(new JLabel("Progression : "), cons);
		cons.gridx = 1;
		add(progressBar, cons);

		cons.gridy = 14;
		cons.gridx = 1;
		add(launch, cons);
	}

	/**
	 * load model from file
	 * @param filename the filename
	 */
	public void loadFromFile(String filename) {
		ArrayList<String> content = new ArrayList<String>();
		try {
			InputStream ips = new FileInputStream(filename + ".mc");
			InputStreamReader ipsr = new InputStreamReader(ips);
			BufferedReader br = new BufferedReader(ipsr);
			String line;
			while ((line = br.readLine()) != null) {
				content.add(line);
			}
			br.close();
			actualPrice.setText(content.get(0));
			strikePrice.setText(content.get(1));
			int val = (int) (Double.parseDouble(content.get(2)) * 10);
			System.out.println("double : " + Double.parseDouble(content.get(2))
					* 10 + "   val : " + val);
			sliderTime.setValue(val);
			interest.setText(content.get(3));
			cost.setText(content.get(4));
			sliderSteps.setValue(Integer.parseInt(content.get(5)));
			sliderSimulation.setValue(Integer.parseInt(content.get(6)));
			volatility.setText(content.get(7));
		} catch (Exception e) {
			System.out.println("Fail to load file " + filename + "   Error : "
					+ e);
		}
	}
}
